package com.zzz.system.service;

import cn.hutool.db.ds.simple.SimpleDataSource;
import cn.hutool.json.JSONUtil;
import com.mybatisflex.core.query.If;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.service.IService;
import com.mybatisflex.core.util.UpdateEntity;
import com.zaxxer.hikari.HikariDataSource;
import com.zzz.framework.config.mybatis.BaseMapperX;
import com.zzz.framework.exception.BizException;
import com.zzz.framework.model.PageResult;
import com.zzz.framework.model.R;
import com.zzz.framework.util.MyBeanUtil;
import com.zzz.system.entity.Datasource;
import com.zzz.system.mapper.DatasourceMapper;
import com.zzz.system.vo.DatasourceVO;
import com.zzz.system.vo.QueryDatasourceVO;
import com.zzz.system.vo.SaveDatasourceVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.zzz.system.entity.table.DatasourceTableDef.*;


@Slf4j
@Service
public class DataSourceService implements IService<Datasource> {
    @Autowired
    private DatasourceMapper datasourceMapper;

    private static Map<String, DataSource> dataSourceMap = new HashMap<>();

    @Override
    public BaseMapperX<Datasource> getMapper() {
        return datasourceMapper;
    }

    public DataSource getDs(String code) {
        DataSource ds = dataSourceMap.get(code);
        if (ds != null) {
            return ds;
        }
        DatasourceVO datasourceVO = findByCode(code);
        if (datasourceVO == null) {
            return null;
        }
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(datasourceVO.getUrl());
        dataSource.setUsername(datasourceVO.getUsername());
        dataSource.setPassword(datasourceVO.getPassword());
        dataSourceMap.put(datasourceVO.getCode(), ds);
        return dataSource;
    }

    public DatasourceVO findByCode(String code) {
        Datasource Datasource = getMapper().selectOneByCode(code);
        return MyBeanUtil.copyBean(Datasource, DatasourceVO.class);
    }

    public List<DatasourceVO> findAll() {
        return MyBeanUtil.copyList(list(), DatasourceVO.class);
    }

    public R add(SaveDatasourceVO saveDatasourceVO) {
        DatasourceVO datasourceVO = this.findByCode(saveDatasourceVO.getCode());
        if (datasourceVO != null) {
            throw new BizException("编号重复");
        }
        Datasource addBean = MyBeanUtil.copyBean(saveDatasourceVO, Datasource.class);
        return R.data(save(addBean));
    }

    public R<String> testConnect(SaveDatasourceVO saveDatasourceVO) {
        try {
            DataSource ds = new SimpleDataSource(saveDatasourceVO.getUrl(),
                    saveDatasourceVO.getUsername(), saveDatasourceVO.getPassword());
            Connection conn = ds.getConnection();
            try {
                conn.close();
            } catch (Exception e) {
                log.warn("关闭连接失败{}", JSONUtil.toJsonStr(saveDatasourceVO));
            }
        } catch (Exception e) {
            return R.error("连接失败");
        }
        return R.data("连接成功");
    }

    public R edit(SaveDatasourceVO saveDatasourceVO) {
        Datasource datasource = getMapper().selectOneById(saveDatasourceVO.getId());
        if (datasource == null) {
            throw new BizException("操作的数据不存在");
        } else if (!saveDatasourceVO.getCode().equals(datasource.getCode())) {
            throw new BizException("编号不能修改");
        }
        Datasource updateBean = UpdateEntity.of(Datasource.class);
        MyBeanUtil.copyBean(saveDatasourceVO, updateBean);
        return R.data(updateById(updateBean));
    }

    public R remove(Long id) {
        Datasource Datasource = getById(id);
        if (Datasource == null) {
            throw new BizException("操作的数据不存在");
        }
        return R.data(removeById(id));
    }

    public PageResult<DatasourceVO> findByCondition(QueryDatasourceVO queryVO) {
        QueryWrapper query = QueryWrapper.create()
                .from(DATASOURCE)
                .where(DATASOURCE.CODE.like(queryVO.getCode(), If::hasText)
                        .and(DATASOURCE.URL.like(queryVO.getUrl(), If::hasText))
                        .and(DATASOURCE.USERNAME.like(queryVO.getUsername(), If::hasText))
                ).orderBy(DATASOURCE.ID, false);
        return getMapper().findByCondition(queryVO.getPage(), queryVO.getPageSize(), query, DatasourceVO.class);
    }
}
